#include "usart.h"

static void USART1_NVIC_Config(void); // 声明USART1_NVIC_Config函数

uint8_t USART1_RX_BUF[USART1_REC_LEN]; // 接受缓冲区，最大为USART1_REC_LEN个字节

// bit15， 接受完成标志
uint16_t USART1_RX_STA = 0; // 接受状态标记

// 重定向C库函数printf到串口，重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
	USART_SendData(USART1, (uint8_t)ch);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
		;

	return (ch);
}

void USART1_SendByte(uint8_t data)
{
	USART_SendData(USART1, data);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
		;
}

// 发送数据到USART1
//  参数:
//    USART1: USART1的指针
//    data: 要发送的数据
void USART1_Tx_String(uint8_t *data)
{
	while (*data != '\0')
	{
		USART_SendData(USART1, *data);
		data++;
	}

	// USART_FLAG_TC表示USART传输完成标志位
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
		;
}

/*
作用:通过DMA1_CH4发送数据到USART1
参数: data: 要发送的数据 , len,发送数据长度
*/
void USART1_DMA_SendString(const char *data)
{
	// 获取消息长度
	int len = strlen(data);

	// 确保要发送的数据大小不超过缓冲区大小
	if (len > LEN_DMA_SEND_BUF)
	{
		len = LEN_DMA_SEND_BUF;
	}

	// 配置USART1的DMA发送方式
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

	// 设置DMA传输的数据长度
	DMA_SetCurrDataCounter(USART1_TX_DMA_Channel, len);

	// 将数据填充到DMA缓冲区
	memset(dma1_ch4_send_buf, 0, LEN_DMA_SEND_BUF); // 清空DMA缓冲区
	memcpy(dma1_ch4_send_buf, data, len);

	// 启用DMA传输通道
	DMA_Cmd(USART1_TX_DMA_Channel, ENABLE);

	// 等待DMA传输完成
	while (DMA_GetFlagStatus(USART1_TX_DMA_FLAG_TC) == RESET)
		;

	// 清除DMA传输完成标志位
	DMA_ClearFlag(USART1_TX_DMA_FLAG_TC);

	// 禁用DMA传输通道
	DMA_Cmd(USART1_TX_DMA_Channel, DISABLE);
}

void USART1_Init(u32 bound)
{
	// GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 使能GPIOA时钟和USART1时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

	// USART1_TX  GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);			// 初始化GPIOA.9

	// USART1_RX  GPIOA.10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;			  // PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);				  // 初始化GPIOA.10

	// 配置串口的工作参数
	USART_InitStructure.USART_BaudRate = bound;										// 串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;						// 字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;							// 一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;								// 无奇偶校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;					// 收发模式
	USART_Init(USART1, &USART_InitStructure);										// 初始化串口1

	// USART1_DMA初始化
	USART1_Tx_DMA1_ch4_Init();

	// 配置串口中断
	USART1_NVIC_Config();
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口接收中断
	USART_Cmd(USART1, ENABLE);					   // 使能串口1
}

static void USART1_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	// 串口中断配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		  // 子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			  // IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);							  // 根据指定的参数初始化VIC寄存器
}

void USART1_IRQHandler(void) // 串口1中断服务函数
{
	uint8_t Res; // 接收到的数据

	if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // 判断USART1的接收中断标志位是否被置位
	{
		Res = USART_ReceiveData(USART1); // 读取接受到的数据

		if ((USART1_RX_STA & 0x8000) == 0) // 接受未完成
		{
			if (USART1_RX_STA < USART1_REC_LEN - 1) // 还可以接受数据
			{
				TIM_SetCounter(TIM1, 0); // 计数器清空

				if (USART1_RX_STA == 0) // 使能定时器1的中断
				{
					TIM_Cmd(TIM1, ENABLE); // 使能定时器1
				}
				USART1_RX_BUF[USART1_RX_STA++] = Res; // 记录接受到值

				if (Res == '\n') // 如果接收到换行符，表示接收完成
				{
					USART1_RX_BUF[USART1_RX_STA] = '\0'; // 在字符串末尾添加结束符
					USART1_RX_STA |= 0x8000;			 // 标记接收完成
				}
			}
			else
			{
				USART1_RX_BUF[USART1_REC_LEN - 1] = '\0'; // 在字符串末尾添加结束符
				USART1_RX_STA |= 0x8000;				  // 强制标记接受完成
			}
		}
	}
}
